home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / pkgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  25.0 KB  |  1,009 lines

  1. #include <alloca.h>
  2. #include <ctype.h>
  3. #include <dirent.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <newt.h>
  7. #include <rpmlib.h>
  8. #include <header.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/types.h>
  12. #include <unistd.h>
  13.  
  14. #include "hash.h"
  15. #include "install.h"
  16. #include "log.h"
  17. #include "pkgs.h"
  18. #include "windows.h"
  19.  
  20. #define FILENAME_TAG 1000000
  21.  
  22. static int selectPackagesByGroup(struct pkgSet * psp);
  23. static int selectPackagesWindow(struct pkgSet * psp, char * group,
  24.                 unsigned int * kSelected);
  25. static int skipPackage(char * name);
  26. static int selectComponents(struct componentSet * csp, struct pkgSet * psp,
  27.                 int * doIndividual);
  28. static int strptrCmp(const void * a, const void * b);
  29. static void showPackageInfo(Header h, unsigned int * kSelected);
  30. static int queryIndividual(int * result);
  31.  
  32. char * skipList[] = { "XFree86-8514", "XFree86-AGX", "XFree86-Mach32",
  33.               "XFree86-Mach64", "XFree86-Mach8", "XFree86-Mono",
  34.               "XFree86-P9000", "XFree86-S3", "XFree86-S3",
  35.               "XFree86-SVGA", "XFree86-VGA16", "XFree86-W32",
  36.               NULL };
  37.  
  38. static int strptrCmp(const void * a, const void * b) {
  39.     const char * const * one = a;
  40.     const char * const * two = b;
  41.  
  42.     return strcmp(*one, *two);
  43. }
  44.  
  45. int pkgCompare(void * first, void * second) {
  46.     struct packageInfo ** a = first;
  47.     struct packageInfo ** b = second;
  48.  
  49.     /* put packages w/o names at the end */
  50.     if (!(*a)->name) return 1;
  51.     if (!(*b)->name) return -1;
  52.  
  53.     return strcmp((*a)->name, (*b)->name);
  54. };
  55.  
  56. int psUsingDirectory(char * dirname, struct pkgSet * psp) {
  57.     DIR * dir;
  58.     struct dirent * ent;
  59.     int fd, rc, isSource;
  60.     Header h;
  61.     int packagesAlloced;
  62.     struct pkgSet ps;
  63.     int count, type;
  64.     unsigned int * sizeptr;
  65.     char * name, * group;
  66.     char * filename;
  67.  
  68.     ps.numPackages = 0;
  69.     packagesAlloced = 5;
  70.     ps.packages = malloc(sizeof(*ps.packages) * packagesAlloced);
  71.  
  72.     logMessage("scanning %s for packages", dirname);
  73.     dir = opendir(dirname);
  74.     if (!dir) {
  75.     errorWindow("error opening directory");
  76.     return INST_ERROR;
  77.     }
  78.  
  79.     errno = 0;
  80.     ent = readdir(dir);
  81.     if (errno) {
  82.     free(ps.packages);
  83.     errorWindow("error reading from directory");
  84.     closedir(dir);
  85.     return INST_ERROR;
  86.     }
  87.  
  88.     filename = alloca(strlen(dirname) + 500);
  89.  
  90.     winStatus(33, 3, "Running", "Scanning available packages...");
  91.  
  92.     while (ent) {
  93.     if (!(ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || 
  94.         ((ent->d_name[1] == '.') && (ent->d_name[2] == '\0'))))) {
  95.         sprintf(filename, "%s/%s", dirname, ent->d_name);
  96.         fd = open(filename, O_RDONLY);
  97.  
  98.         if (fd < 0) {
  99.         logMessage("failed to open %s: %s", filename,
  100.                strerror(errno));
  101.         } else {
  102.         rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
  103.  
  104.         close(fd);
  105.         if (rc) {
  106.             logMessage("failed to rpmReadPackageHeader %s:", 
  107.                 ent->d_name);
  108.         } else {
  109.             if (ps.numPackages == packagesAlloced) {
  110.             packagesAlloced += 5;
  111.             ps.packages = realloc(ps.packages,
  112.                 sizeof(*ps.packages) * packagesAlloced);
  113.             }
  114.  
  115.             ps.packages[ps.numPackages] = 
  116.                 malloc(sizeof(struct packageInfo));
  117.             ps.packages[ps.numPackages]->h = h;
  118.             ps.packages[ps.numPackages]->selected = 0;
  119.             ps.packages[ps.numPackages]->data = strdup(ent->d_name);
  120.  
  121.             headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, 
  122.                     &count);
  123.             if (headerGetEntry(h, RPMTAG_SIZE, &type, (void **) 
  124.                   &sizeptr, &count))
  125.             ps.packages[ps.numPackages]->size = *sizeptr;
  126.             else
  127.             ps.packages[ps.numPackages]->size = 0;
  128.  
  129.             if (skipPackage(name)) 
  130.             ps.packages[ps.numPackages]->inmenu = 0;
  131.             else
  132.             ps.packages[ps.numPackages]->inmenu = 1;
  133.  
  134.             if (!headerGetEntry(h, RPMTAG_GROUP, &type, 
  135.                     (void **) &group, &count)) {
  136.             group = "(unknown group)";
  137.             } else if (!strlen(group)) {
  138.             group = "(unknown group)";
  139.             }
  140.  
  141.             ps.packages[ps.numPackages]->name = name;
  142.             ps.packages[ps.numPackages]->group = group;
  143.     
  144.             ps.numPackages++;
  145.         }
  146.         }
  147.     }
  148.  
  149.     errno = 0;
  150.     ent = readdir(dir);
  151.     if (errno) {
  152.         newtPopWindow();
  153.         errorWindow("error reading from directory (2): %s");
  154.         free(ps.packages);
  155.         closedir(dir);
  156.         return INST_ERROR;
  157.     }
  158.     } 
  159.  
  160.     *psp = ps;
  161.  
  162.     qsort(ps.packages, ps.numPackages, sizeof(*ps.packages), 
  163.       (void *) pkgCompare);
  164.     
  165.     closedir(dir);
  166.  
  167.     newtPopWindow();
  168.  
  169.     return 0;
  170. }
  171.  
  172. int psReadComponentsFile(char * filespec, struct pkgSet * psp, 
  173.              struct componentSet * csp) {
  174.     FILE * f;
  175.     char buf[255];
  176.     int inComp;
  177.     int line = 0;
  178.     char * start;
  179.     char * chptr;
  180.     int compsAlloced;
  181.     int packagesAlloced = 0;
  182.     struct componentSet cs;
  183.     struct component * currcomp = NULL;
  184.     struct packageInfo packkey, ** pack;
  185.     struct packageInfo * keyaddr = &packkey;
  186.     int i;
  187.     int preskelNum = 0;
  188.     int baseNum = 0;
  189.  
  190.     f = fopen(filespec, "r");
  191.     if (!f) {
  192.     errorWindow("Cannot open components file: %s");
  193.     return INST_ERROR;
  194.     }
  195.   
  196.     /* get the version number */
  197.     line++;
  198.     if (!fgets(buf, sizeof(buf), f)) {
  199.     errorWindow("Cannot read components file: %s");
  200.     fclose(f);
  201.     return INST_ERROR;
  202.     }
  203.  
  204.     if (strcmp(buf, "0\n")) {
  205.     messageWindow("Error", "Comps file is not version 0 as expected");
  206.     fclose(f);
  207.     return INST_ERROR;
  208.     }
  209.  
  210.     compsAlloced = 5;
  211.     cs.numComponents = 0;
  212.     cs.comps = malloc(sizeof(*cs.comps) * compsAlloced);
  213.     cs.preskel = NULL;
  214.     cs.base = NULL;
  215.  
  216.     inComp = 0;
  217.     while (fgets(buf, sizeof(buf), f)) {
  218.     line++;
  219.  
  220.     /* remove any trailing '\n', leave chptr at the end of the string */
  221.     chptr = buf + strlen(buf) - 1;
  222.     if (*chptr == '\n') 
  223.         *chptr = '\0';
  224.     else
  225.         chptr++;
  226.  
  227.     /* strip leading spaces */
  228.     start = buf;
  229.     while (*start && isspace(*start)) start++;
  230.  
  231.     /* empty string */
  232.     if (!*start) continue;
  233.     
  234.     /* comment */
  235.     if (*start == '#') continue;
  236.  
  237.     if (!inComp) {
  238.         /* first digit must be a zero or a one */
  239.         if (*start != '0' && *start != '1') {
  240.         messageWindow("Error", "bad comps file at line %d", line);
  241.         continue;
  242.         }
  243.  
  244.         if (compsAlloced == cs.numComponents) {
  245.         compsAlloced += 5;
  246.         cs.comps = realloc(cs.comps, sizeof(*cs.comps) * compsAlloced);
  247.         }
  248.  
  249.         currcomp = cs.comps + cs.numComponents;
  250.         currcomp->selected = (*start == '1');
  251.         currcomp->inmenu = 1;
  252.  
  253.         start++;
  254.         while (*start && isspace(*start)) start++;
  255.  
  256.         if (!*start) {
  257.         messageWindow("comps Error", 
  258.                 "missing component name at line %d", line);
  259.         continue;
  260.         }
  261.  
  262.         currcomp->name = strdup(start);
  263.  
  264.         currcomp->ps.numPackages = 0;
  265.         packagesAlloced = 5;
  266.         currcomp->ps.packages = malloc(
  267.         sizeof(struct packageInfo) * packagesAlloced);
  268.         inComp = 1;
  269.     } else {
  270.         if (!strcmp(start, "end")) {
  271.         inComp = 0;
  272.  
  273.         if (!strcasecmp(currcomp->name, "*beforeskel*"))
  274.             preskelNum = cs.numComponents;
  275.         else if (!strcasecmp(currcomp->name, "Base"))
  276.             baseNum = cs.numComponents;
  277.  
  278.         cs.numComponents++;
  279.         } else {
  280.         packkey.name = start;
  281.         pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
  282.                 sizeof(*psp->packages), (void *) pkgCompare);
  283.         if (!pack) {
  284.             messageWindow("comps Error", 
  285.                     "package %s at line %d dne", start, line);
  286.             continue;
  287.         }
  288.  
  289.         if (currcomp->ps.numPackages == packagesAlloced) {
  290.             packagesAlloced += 5;
  291.             currcomp->ps.packages = realloc(currcomp->ps.packages,
  292.             sizeof(struct packageInfo) * packagesAlloced);
  293.         }
  294.  
  295.         currcomp->ps.packages[currcomp->ps.numPackages] = *pack;
  296.         currcomp->ps.numPackages++;
  297.         }
  298.     }
  299.     }
  300.  
  301.     fclose(f);
  302.  
  303.     cs.base = cs.comps + baseNum;
  304.     cs.preskel = cs.comps + preskelNum;
  305.  
  306.     cs.base->inmenu = 0;
  307.     cs.preskel->inmenu = 0;
  308.     cs.base->selected = 1;
  309.     cs.preskel->selected = 1;
  310.  
  311.     for (i = 0; i < cs.base->ps.numPackages; i++) {
  312.     cs.base->ps.packages[i]->inmenu = 0;
  313.     cs.base->ps.packages[i]->selected = 1;
  314.     }
  315.  
  316.     for (i = 0; i < cs.preskel->ps.numPackages; i++) {
  317.     cs.preskel->ps.packages[i]->inmenu = 0;
  318.     cs.preskel->ps.packages[i]->selected = 1;
  319.     }
  320.  
  321.     *csp = cs;
  322.  
  323.     return 0;
  324. }
  325.  
  326. struct packageCheckbox {
  327.     newtComponent cb, sizeLabel;
  328.     unsigned int * kSelected;
  329.     unsigned int size;
  330.     char state, lastState;
  331. };
  332.  
  333. static void sizeCallback(newtComponent co, struct packageCheckbox * cbi) {
  334.     char sizeBuf[20];
  335.  
  336.     if (cbi->state != cbi->lastState) {
  337.     if (cbi->state == ' ') 
  338.         *cbi->kSelected -= cbi->size / 1024;
  339.     else
  340.         *cbi->kSelected += cbi->size / 1024;
  341.     cbi->lastState = cbi->state;
  342.  
  343.     sprintf(sizeBuf, "%dM", *cbi->kSelected / 1024);
  344.     newtLabelSetText(cbi->sizeLabel, sizeBuf);
  345.     newtRefresh();
  346.     }
  347. }
  348.  
  349. static int selectPackagesWindow(struct pkgSet * psp, char * group,
  350.                 unsigned int * kSelected) {
  351.     newtComponent okay, form, checkList, sb, cancel, current, size;
  352.     struct packageCheckbox * cbs;
  353.     int i, row, groupLength, rc;
  354.     char val;
  355.     struct newtExitStruct answer;
  356.     int done = 0;
  357.     char sizeBuf[20];
  358.  
  359.     if (!group) {
  360.     group = "";
  361.     groupLength = 0;
  362.     } else
  363.     groupLength = strlen(group);
  364.  
  365.     cbs = alloca(sizeof(*cbs) * psp->numPackages);
  366.  
  367.     newtOpenWindow(22, 4, 40, 16, "Select Packages");
  368.     newtPushHelpLine("<F1> will show you a size and description of a package");
  369.  
  370.     form = newtForm(NULL, NULL, 0);
  371.     okay = newtButton(6, 12, "Ok");
  372.     cancel = newtButton(21, 12, "Cancel");
  373.  
  374.     newtFormAddComponent(form, newtLabel(1, 1, 
  375.             "What packages should be installed?"));
  376.     newtFormAddComponent(form, newtLabel(1, 10, 
  377.             "Size of all selected packages:"));
  378.     sprintf(sizeBuf, "%dM", *kSelected / 1024);
  379.     size = newtLabel(32, 10, sizeBuf);
  380.     newtFormAddComponent(form, size);
  381.  
  382.     sb = newtVerticalScrollbar(32, 3, 6, 9, 10);
  383.     checkList = newtForm(sb, NULL, 0);
  384.     newtFormSetBackground(checkList, NEWT_COLORSET_CHECKBOX);
  385.  
  386.     for (i = 0, row = 0; i < psp->numPackages; i++) {
  387.     if (psp->packages[i]->inmenu &&
  388.         strlen(psp->packages[i]->group) >= groupLength &&
  389.         !strncmp(psp->packages[i]->group, group, groupLength)) {
  390.         if (psp->packages[i]->selected)
  391.         val = '*';
  392.         else
  393.         val = ' ';
  394.  
  395.         cbs[i].cb = newtCheckbox(6, 3 + row++, psp->packages[i]->name, val, 
  396.                      NULL, &cbs[i].state);
  397.         newtComponentAddCallback(cbs[i].cb, (void *) sizeCallback, cbs + i);
  398.         cbs[i].sizeLabel = size;
  399.         cbs[i].lastState = cbs[i].state = val;
  400.         cbs[i].size = psp->packages[i]->size;
  401.         cbs[i].kSelected = kSelected;
  402.         newtFormAddComponent(checkList, cbs[i].cb);
  403.     } else {
  404.         cbs[i].state = ' ';
  405.         cbs[i].cb = NULL;
  406.     }
  407.     }
  408.  
  409.     if (row > 6) {
  410.     newtFormSetHeight(checkList, 6);
  411.     newtFormAddComponent(checkList, sb);
  412.     } else
  413.     newtFormSetWidth(checkList, 27);
  414.  
  415.     newtFormAddComponents(form, checkList, okay, cancel, NULL);
  416.  
  417.     newtFormAddHotKey(form, NEWT_KEY_F1);
  418.  
  419.     rc = 0;
  420.     while (!done) {
  421.     newtFormRun(form, &answer);
  422.  
  423.     if (answer.reason == NEWT_EXIT_HOTKEY) {
  424.         if (answer.u.key == NEWT_KEY_F12) 
  425.         done = 1;
  426.         else if (answer.u.key == NEWT_KEY_F1) {
  427.         current = newtFormGetCurrent(checkList);
  428.         for (i = 0; i < psp->numPackages; i++) {
  429.             if (cbs[i].cb == current) {
  430.             showPackageInfo(psp->packages[i]->h, kSelected);
  431.             break;
  432.             }
  433.         }
  434.         }
  435.     } else if (answer.reason == NEWT_EXIT_COMPONENT) {
  436.         done = 1;
  437.         if (answer.u.co == cancel)
  438.         rc = INST_CANCEL;
  439.     }
  440.     }
  441.  
  442.     newtFormDestroy(form);
  443.     newtPopWindow();
  444.     newtPopHelpLine();
  445.  
  446.     if (rc) return rc;
  447.  
  448.     for (i = 0; i < psp->numPackages; i++) 
  449.     if (cbs[i].cb)
  450.         if (cbs[i].state != ' ')
  451.            psp->packages[i]->selected = 1;
  452.         else
  453.            psp->packages[i]->selected = 0;
  454.  
  455.     return 0;
  456. }
  457.  
  458. #define SELECT_COMPONENTS    1
  459. #define SELECT_PACKAGES        2
  460. #define SELECT_VERIFY        3
  461. #define SELECT_DONE        100
  462.  
  463. int psSelectPackages(struct pkgSet * psp, struct componentSet * csp,
  464.              int goForward, int isUpgrade) {
  465.     int rc;
  466.     int stage;
  467.     static int doIndividual = 0;
  468.  
  469.     if (!goForward && doIndividual)
  470.     stage = SELECT_PACKAGES;
  471.     else
  472.     stage = SELECT_COMPONENTS;
  473.  
  474.     while (stage != SELECT_DONE) {
  475.     switch (stage) {
  476.       case SELECT_COMPONENTS:
  477.         if (isUpgrade)
  478.         rc = queryIndividual(&doIndividual);
  479.         else
  480.         rc = selectComponents(csp, psp, &doIndividual);
  481.         if (rc) return rc;
  482.         if (doIndividual)
  483.         stage = SELECT_PACKAGES;
  484.         else
  485.         stage = SELECT_VERIFY;
  486.         break;
  487.  
  488.       case SELECT_PACKAGES:
  489.         rc = selectPackagesByGroup(psp);
  490.         if (rc == INST_CANCEL) 
  491.         stage = SELECT_COMPONENTS;
  492.         else if (rc) 
  493.         return rc;
  494.         else
  495.         stage = SELECT_VERIFY;
  496.         break;
  497.  
  498.       case SELECT_VERIFY:
  499.         rc = psVerifyDependencies(psp, 0);
  500.         if (rc == INST_ERROR) 
  501.         return rc;
  502.         else if (rc)
  503.         stage = SELECT_PACKAGES;
  504.         else
  505.         stage = SELECT_DONE;
  506.     }
  507.     } 
  508.  
  509.     return 0;
  510. }
  511.  
  512. int psVerifyDependencies(struct pkgSet * psp, int fixup) {
  513.     rpmdb db = NULL;
  514.     rpmDependencies rpmdeps;
  515.     int i;
  516.     struct rpmDependencyConflict * conflicts;
  517.     struct packageInfo * package;
  518.     int numConflicts;
  519.     newtComponent okay, form, textbox, info, cancel, answer;
  520.     char * text, buf[80];
  521.     char selectPackages;
  522.  
  523.     if (!access("/mnt/var/lib/rpm/packages.rpm", R_OK))
  524.     if (rpmdbOpen("/mnt", &db, O_RDWR | O_CREAT, 0644))
  525.         db = NULL;
  526.  
  527.     rpmdeps = rpmdepDependencies(db);
  528.  
  529.     for (i = 0; i < psp->numPackages; i++) {
  530.     if (psp->packages[i]->selected)
  531.         rpmdepAddPackage(rpmdeps, psp->packages[i]->h);
  532.     else
  533.         rpmdepAvailablePackage(rpmdeps, psp->packages[i]->h, 
  534.                    psp->packages[i]);
  535.     }
  536.  
  537.     rpmdepCheck(rpmdeps, &conflicts, &numConflicts);
  538.  
  539.     rpmdepDone(rpmdeps);
  540.     if (db) rpmdbClose(db);
  541.  
  542.     if (!numConflicts) {
  543.     return 0;
  544.     }
  545.  
  546.     if (fixup) {
  547.     for (i = 0; i < numConflicts; i++) {
  548.         package = conflicts[i].suggestedPackage;
  549.         if (package) package->selected = 1;
  550.     }
  551.  
  552.     rpmdepFreeConflicts(conflicts, numConflicts);
  553.  
  554.     return 0;
  555.     }
  556.  
  557.     text = malloc(80 * numConflicts);
  558.     *text = '\0';
  559.     for (i = 0; i < numConflicts; i++) {
  560.     package = conflicts[i].suggestedPackage;
  561.     if (package)
  562.         sprintf(buf, "%-20s %-20s", conflicts[i].byName, 
  563.             package->name);
  564.     else
  565.         sprintf(buf, "%-20s (no suggestion)", conflicts[i].byName);
  566.  
  567.     if (i) strcat(text, "\n");
  568.     strcat(text, buf);
  569.     }
  570.  
  571.     newtOpenWindow(15, 2, 50, 19, "Unresolved Dependencies");
  572.     
  573.     form = newtForm(NULL, NULL, 0);
  574.  
  575.     info = newtTextbox(1, 1, 45, 4, NEWT_TEXTBOX_WRAP);
  576.     newtTextboxSetText(info, 
  577.     "Some of the packages you have selected to install require "
  578.     "packages you have not selected. If you just select Ok "
  579.     "all of those required packages will be installed.");
  580.  
  581.     sprintf(buf, "%-20s %-20s", "Package", "Requirement");
  582.     okay = newtButton(10, 15, "Ok");
  583.     cancel = newtButton(30, 15, "Cancel");
  584.     newtFormAddComponent(form, newtLabel(3, 6, buf));
  585.     textbox = newtTextbox(3, 7, 45, 5, NEWT_TEXTBOX_SCROLL);
  586.     newtTextboxSetText(textbox, text); 
  587.     newtFormAddComponent(form, 
  588.     newtCheckbox(3, 13, "Install packages to satisfy dependencies", '*',
  589.              NULL, &selectPackages));
  590.     newtFormAddComponents(form, info, textbox, okay, cancel, NULL);
  591.     newtFormSetCurrent(form, okay);
  592.  
  593.     answer = newtRunForm(form);
  594.  
  595.     newtFormDestroy(form);
  596.     newtPopWindow();
  597.  
  598.     if (answer == cancel) {
  599.     free(conflicts);
  600.     return INST_CANCEL;
  601.     }
  602.  
  603.     if (selectPackages != ' ') {
  604.     for (i = 0; i < numConflicts; i++) {
  605.         package = conflicts[i].suggestedPackage;
  606.         if (package) package->selected = 1;
  607.     }
  608.     }
  609.  
  610.     free(conflicts);
  611.     
  612.     return 0;
  613. } ;
  614.  
  615. static int selectComponents(struct componentSet * csp, struct pkgSet * psp,
  616.                 int * doIndividual) {
  617.     int i, j;
  618.     newtComponent okay, form, checklist, checkbox, sb, cancel, answer;
  619.     char val, individualPackages, everything;
  620.     char * states;
  621.     int row;
  622.  
  623.     individualPackages = *doIndividual ? '*' : ' ';
  624.  
  625.     states = alloca(sizeof(*states) * csp->numComponents);
  626.  
  627.     newtOpenWindow(15, 2, 50, 19, "Components to Install");
  628.  
  629.     form = newtForm(NULL, NULL, 0);
  630.  
  631.     newtFormAddComponent(form, newtLabel(1, 1, 
  632.                 "Choose components to install:"));
  633.     /*newtFormAddComponent(form, newtLabel(36, 1, "Size:"));
  634.     size = newtLabel(1, 42,*/
  635.  
  636.     sb = newtVerticalScrollbar(47, 3, 9, 9, 10);
  637.     checklist = newtForm(sb, NULL, 0);
  638.     newtFormSetHeight(checklist, 9);
  639.     newtFormSetBackground(checklist, NEWT_COLORSET_CHECKBOX);
  640.     newtFormAddComponent(checklist, sb);
  641.  
  642.     for (i = 0, row = 0; i < csp->numComponents; i++) {
  643.     if (csp->comps[i].inmenu) {
  644.         if (csp->comps[i].selected)
  645.         val = '*';
  646.         else
  647.         val = ' ';
  648.  
  649.         checkbox = newtCheckbox(6, 3 + row++, csp->comps[i].name, val, 
  650.                     NULL, &states[i]);
  651.         newtFormAddComponent(checklist, checkbox);
  652.     } else 
  653.         states[i] = ' ';
  654.     }
  655.  
  656.     checkbox = newtCheckbox(6, 3 + row++, "Everything", ' ', 
  657.                 NULL, &everything);
  658.     newtFormAddComponent(checklist, checkbox);
  659.  
  660.     checkbox = newtCheckbox(10, 13, "Select individual packages", 
  661.                 individualPackages, NULL, &individualPackages);
  662.  
  663.     okay = newtButton(10, 15, "Ok");
  664.     cancel = newtButton(30, 15, "Cancel");
  665.  
  666.     newtFormAddComponents(form, checklist, checkbox, okay, cancel, NULL);
  667.  
  668.     answer = newtRunForm(form);
  669.  
  670.     newtFormDestroy(form);
  671.     newtPopWindow();
  672.  
  673.     if (answer == cancel) return INST_CANCEL;
  674.  
  675.     *doIndividual = (individualPackages != ' ');
  676.  
  677.     if (everything != ' ') {
  678.     for (i = 0; i < psp->numPackages; i++)
  679.         psp->packages[i]->selected = 1;
  680.     }
  681.  
  682.     for (i = 0; i < csp->numComponents; i++) {
  683.     if (csp->comps[i].inmenu) {
  684.         if (states[i] != ' ')
  685.         csp->comps[i].selected = 1;
  686.         else
  687.         csp->comps[i].selected = 0;
  688.  
  689.         for (j = 0; j < csp->comps[i].ps.numPackages; j++)
  690.         csp->comps[i].ps.packages[j]->selected |= 
  691.             csp->comps[i].selected;
  692.     }
  693.     }
  694.  
  695.     return 0;
  696. }
  697.  
  698. void psFreeComponentSet(struct componentSet * csp) {
  699.     int i;
  700.     struct component * currcomp;
  701.  
  702.     currcomp = csp->comps;
  703.     for (i = 0; i < csp->numComponents; i++, currcomp++) {
  704.     free(currcomp->ps.packages);
  705.     }
  706.  
  707.     free(csp->comps);
  708. }
  709.  
  710. int psFromHeaderListDesc(int fd, struct pkgSet * psp, int noSeek) {
  711.     struct pkgSet ps;
  712.     int end, type, count;
  713.     unsigned int * sizeptr;
  714.     Header h;
  715.     int packagesAlloced;
  716.     char * name, * group;
  717.     int done = 0;
  718.  
  719.     ps.numPackages = 0;
  720.     packagesAlloced = 5;
  721.     ps.packages = malloc(sizeof(*ps.packages) * packagesAlloced);
  722.  
  723.     if (!noSeek) {
  724.     count = lseek(fd, 0, SEEK_CUR);
  725.     end = lseek(fd, 0, SEEK_END); 
  726.     lseek(fd, count, SEEK_SET); 
  727.     }
  728.  
  729.     while (!done) {
  730.     h = headerRead(fd, HEADER_MAGIC_YES);
  731.     if (!h && noSeek) {
  732.         done = 1;
  733.     } else if (!h) {
  734.         messageWindow("Error", "error reading header at %d\n", 
  735.             (int) lseek(fd, 0, SEEK_CUR));
  736.         free(ps.packages);
  737.         return INST_ERROR;
  738.     } else {
  739.         headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
  740.  
  741.         if (!headerGetEntry(h, RPMTAG_GROUP, &type, (void **) &group, 
  742.                 &count)) {
  743.         group = "(unknown group)";
  744.         } else if (!strlen(group))
  745.         group = "(unknown group)";
  746.  
  747.         if (ps.numPackages == packagesAlloced) {
  748.         packagesAlloced += 5;
  749.         ps.packages = realloc(ps.packages,
  750.             sizeof(*ps.packages) * packagesAlloced);
  751.         }
  752.  
  753.         ps.packages[ps.numPackages] = 
  754.             malloc(sizeof(struct packageInfo));
  755.         ps.packages[ps.numPackages]->h = h;
  756.         ps.packages[ps.numPackages]->selected = 0;
  757.  
  758.         if (headerGetEntry(h, RPMTAG_SIZE, &type, (void **) &sizeptr, 
  759.                 &count))
  760.         ps.packages[ps.numPackages]->size = *sizeptr;
  761.         else
  762.         ps.packages[ps.numPackages]->size = 0;
  763.  
  764.         if (skipPackage(name)) 
  765.         ps.packages[ps.numPackages]->inmenu = 0;
  766.         else
  767.         ps.packages[ps.numPackages]->inmenu = 1;
  768.  
  769.         ps.packages[ps.numPackages]->name = name;
  770.         ps.packages[ps.numPackages]->group = group;
  771.         headerGetEntry(h, FILENAME_TAG, &type,
  772.              (void **) &ps.packages[ps.numPackages]->data, 
  773.              &count);
  774.  
  775.         ps.numPackages++;
  776.     }
  777.  
  778.     if (!noSeek) {
  779.         if (end <= lseek(fd, 0, SEEK_CUR)) 
  780.         done = 1;
  781.     }
  782.     }
  783.  
  784.     logMessage("psFromHeaderListDesc read %d headers", ps.numPackages);
  785.  
  786.     *psp = ps;
  787.  
  788.     qsort(ps.packages, ps.numPackages, sizeof(*ps.packages), 
  789.       (void *) pkgCompare);
  790.     
  791.     return 0;
  792. }
  793.  
  794. int psFromHeaderListFile(char * file, struct pkgSet * psp) {
  795.     int fd, rc;
  796.  
  797.     fd = open(file, O_RDONLY, 0644);
  798.     if (fd < 0) {
  799.     errorWindow("error opening header file: %s");
  800.     return INST_ERROR;
  801.     }
  802.  
  803.     rc = psFromHeaderListDesc(fd, psp, 0);
  804.     close(fd);
  805.  
  806.     return rc;
  807. }
  808.  
  809. static int skipPackage(char * name) {
  810.     char ** item;
  811.  
  812.     for (item = skipList; *item; item++) {
  813.     if (!strcmp(*item, name)) return 1;
  814.     }
  815.  
  816.     return 0;
  817. }
  818.  
  819. static int selectPackagesByGroup(struct pkgSet * psp) {
  820.     newtComponent okay, form, listbox, cancel, answer;
  821.     newtComponent sizeLabel;
  822.     int i, row, numGroups;
  823.     unsigned int kSelected = 0;
  824.     int rc = 0;
  825.     hashTable ht;
  826.     htIterator iter;
  827.     char buf[200], * chptr;
  828.     char * group;
  829.     char ** groupList;
  830.  
  831.     ht = htNewTable(psp->numPackages);
  832.     for (i = 0, row = 0; i < psp->numPackages; i++) {
  833.     group = psp->packages[i]->group;
  834.     chptr = group;
  835.     while (*chptr && *chptr != '/') chptr++;
  836.     if (*chptr == '/') {
  837.         chptr++;
  838.         while (*chptr && *chptr != '/') chptr++;
  839.         if (*chptr == '/') {
  840.         strncpy(buf, group, chptr - group);
  841.         buf[chptr - group] = '\0';
  842.         group = buf;
  843.         }
  844.     }
  845.  
  846.     htAddToTable(ht, group);
  847.  
  848.     if (psp->packages[i]->selected)
  849.         kSelected += (psp->packages[i]->size / 1024);
  850.     }
  851.  
  852.     numGroups = htNumEntries(ht);
  853.     groupList = alloca(sizeof(*groupList) * numGroups);
  854.     htIterStart(&iter);
  855.     i = 0;
  856.     while (htIterGetNext(ht, &iter, &group)) {
  857.     groupList[i] = alloca(strlen(group) + 1);
  858.     strcpy(groupList[i], group);
  859.     i++;
  860.     }
  861.  
  862.     qsort(groupList, numGroups, sizeof(char *), strptrCmp);
  863.     htFreeHashTable(ht);
  864.  
  865.     newtOpenWindow(4, 2, 45, 14, "Select Group");
  866.  
  867.     form = newtForm(NULL, NULL, 0);
  868.     okay = newtButton(7, 10, "Ok");
  869.     cancel = newtButton(23, 10, "Cancel");
  870.  
  871.     newtFormAddComponent(form, newtLabel(1, 1, 
  872.             "Choose a group to examine:"));
  873.     newtFormAddComponent(form, newtLabel(33, 1,
  874.             "Size:"));
  875.     sprintf(buf, "%dM", kSelected / 1024);
  876.     sizeLabel = newtLabel(39, 1, buf);
  877.     newtFormAddComponent(form, sizeLabel);
  878.  
  879.     listbox = newtListbox(3, 3, 6, NEWT_LISTBOX_RETURNEXIT);
  880.  
  881.     for (i = 0; i < numGroups; i++) {
  882.     newtListboxAddEntry(listbox, groupList[i], groupList[i]);
  883.     }
  884.  
  885.     newtFormAddComponents(form, listbox, okay, cancel, NULL);
  886.  
  887.     do {
  888.     answer = newtRunForm(form);
  889.     if (answer == listbox) {
  890.         group = newtListboxGetCurrent(listbox);
  891.         rc = selectPackagesWindow(psp, group, &kSelected);
  892.  
  893.         sprintf(buf, "%dM", kSelected / 1024);
  894.         newtLabelSetText(sizeLabel, buf);
  895.     }
  896.     } while (answer == listbox && rc != INST_ERROR);
  897.  
  898.     newtFormDestroy(form);
  899.     newtPopWindow();
  900.  
  901.     if (rc == INST_ERROR) return rc;
  902.  
  903.     if (answer == cancel) return INST_CANCEL;
  904.  
  905.     return 0;
  906. }
  907.  
  908. static void showPackageInfo(Header h, unsigned int * kSelected) {
  909.     newtComponent form, textbox, okay;
  910.     char * name, * version, * description, * release;
  911.     uint_32 * size;
  912.     int type, count;
  913.     char infostr[255];
  914.     char * buf, * from, * to;
  915.  
  916.     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
  917.     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
  918.     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
  919.  
  920.     if (!headerGetEntry(h, RPMTAG_SIZE, &type, (void **) &size, &count))
  921.     size = 0;
  922.  
  923.     if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, (void **) &description, 
  924.         &count)) {
  925.     if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, (void **) &description, 
  926.         &count)) {
  927.         description = "(none available)";
  928.     }
  929.     }
  930.  
  931.     newtOpenWindow(31, 6, 45, 15, name);
  932.  
  933.     form = newtForm(NULL, NULL, 0);
  934.     newtFormAddComponent(form, newtLabel(1, 1, "Package:"));
  935.     newtFormAddComponent(form, newtLabel(1, 2, "Size   :"));
  936.  
  937.     sprintf(infostr, "%s-%s-%s", name, version, release);
  938.     newtFormAddComponent(form, newtLabel(10, 1, infostr));
  939.     sprintf(infostr, "%d", *size);
  940.     newtFormAddComponent(form, newtLabel(10, 2, infostr));
  941.  
  942.     to = buf = alloca(strlen(description) + 1);
  943.     from = description; 
  944.     /* Rip out all '\n' that don't start new paragraphs */
  945.     while (*from) {
  946.     if (*from == '\n') {
  947.         if ((*(from + 1) && isspace(*(from + 1))) ||
  948.         (from > description && *(from - 1) == '\n'))
  949.         *to++ = '\n';
  950.         else
  951.         *to++ = ' ';
  952.     } else
  953.         *to++ = *from;
  954.     from++;
  955.     }
  956.     *to = '\0';
  957.  
  958.     textbox = newtTextbox(1, 4, 43, 6, NEWT_TEXTBOX_WRAP | 
  959.                 NEWT_TEXTBOX_SCROLL);
  960.     newtTextboxSetText(textbox, buf);
  961.  
  962.     okay = newtButton(20, 11, "Ok");
  963.     newtFormAddComponents(form, textbox, okay, NULL);
  964.  
  965.     newtRunForm(form);
  966.  
  967.     newtFormDestroy(form);
  968.     newtPopWindow();
  969. }
  970.  
  971. static int queryIndividual(int * result) {
  972.     newtComponent text, yes, no, cancel, form;
  973.     struct newtExitStruct answer;
  974.     int rc = 0;
  975.  
  976.     *result = 0;
  977.  
  978.     newtOpenWindow(17, 4, 45, 15, "Upgrade Packages");
  979.     text = newtTextbox(1, 1, 40, 10, NEWT_TEXTBOX_WRAP);
  980.     newtTextboxSetText(text,
  981.     "The packages you have installed, and any other packages which are "
  982.     "needed to satisfy their dependencies, have been selected for "
  983.     "installation. Would you like to customize the set of packages that "
  984.     "will be upgraded?");
  985.  
  986.     yes = newtButton(4, 10, "Yes");
  987.     no = newtButton(18, 10, "No");
  988.     cancel = newtButton(32, 10, "Cancel");
  989.  
  990.     form = newtForm(NULL, NULL, 0);
  991.     newtFormAddComponents(form, text, yes, no, cancel, NULL);
  992.     
  993.     newtFormRun(form, &answer);
  994.  
  995.     newtFormDestroy(form);
  996.     newtPopWindow();
  997.  
  998.     if (answer.reason == NEWT_EXIT_HOTKEY && answer.u.key == NEWT_KEY_F12) {
  999.     *result = 1;
  1000.     } else if (answer.reason == NEWT_EXIT_COMPONENT) {
  1001.     if (answer.u.co == cancel) 
  1002.         rc = 1;
  1003.     else if (answer.u.co == yes)
  1004.         *result = 1;
  1005.     }
  1006.  
  1007.     return rc;
  1008. }
  1009.